#include "jsonrpcsocket.h"

#include <QIODevice>
#include <QJsonDocument>
#include <QRegularExpression>
#include <QStringList>
#include <QMetaClassInfo>
#include <QDebug>

#include "jsonrpcresponsehandler.h"
#include "jsonrpcnotificationhandler.h"

JsonRpcSocket::JsonRpcSocket(QIODevice *device, QObject *parent) : QObject(parent){
    p_device = device;

    connect(device, SIGNAL(readyRead()), this, SLOT(processIncomingData()));
}


void JsonRpcSocket::sendMessage(const JsonRpcMessage& message){
    QJsonDocument doc(message.v_object);
    QByteArray messageData;
    messageData = doc.toJson();
    p_device->write(messageData);
}


JsonRpcResponseHandler* JsonRpcSocket::invokeMethod(const QString& methodName, const QVariant& arg1, const QVariant& arg2, const QVariant& arg3){

    QVariantList paramList;
    if(arg1.isValid()) paramList.append(arg1);
    if(arg2.isValid()) paramList.append(arg2);
    if(arg3.isValid()) paramList.append(arg3);

    QString normalizedMethodName = methodName;
    JsonRpcMessage message = JsonRpcMessage::createRequest(normalizedMethodName, paramList);
    JsonRpcResponseHandler *reply = new JsonRpcResponseHandler(message.id());
    this->sendMessage(message);
    v_currentRequest.insert(message.id(), reply);

    return reply;
}


JsonRpcNotificationHandler* JsonRpcSocket::handleNotification(const QString& methodName, QObject *instance, const char *slot, bool automaticHandle){

    JsonRpcNotificationHandler *handle = new JsonRpcNotificationHandler(methodName, instance, slot);

    handle->setAutomaticHandle(automaticHandle);
    //v_notificationMutex.lock();
    //v_notificationHandlerMap.insert(methodName, handle);
    //v_notificationMutex.unlock();
    return handle;
}


void JsonRpcSocket::processIncomingData(){
    v_lastObjectPart.append(p_device->readAll());

    int counter = 0;
    const char *ptr = v_lastObjectPart.constData();
    int position = 0;

    QList<QByteArray> objects;

    while(position <= v_lastObjectPart.length()){
        if(ptr[position] == '{') counter++;
        else if(ptr[position] == '}'){
            counter--;
            if(counter == 0){
                objects << v_lastObjectPart.left(position+1);
                v_lastObjectPart = v_lastObjectPart.mid(position+1);
                ptr = v_lastObjectPart.constData();
                position = 0;
            }
        }
        position++;
    }

    QJsonParseError error;


    QList<QByteArray>::const_iterator it;
    for(it = objects.constBegin(); it != objects.constEnd(); it++){

        //qDebug() << "JSON=" << *it;
        QJsonDocument json = QJsonDocument::fromJson(*it, &error);
        if(error.error != QJsonParseError::NoError || json.isEmpty()){
            qDebug() << "Error while parsing JSON object";
        }
        JsonRpcMessage message(json.object());

        if(message.type() == JsonRpcMessage::Request){
            Q_EMIT jsonRpcRequestReceived(message);
        }else if(message.type() == JsonRpcMessage::Notification){
            v_notificationMutex.lock();
            if(!v_notificationHandlerMap.contains(message.method())) return;
            JsonRpcNotificationHandler *notif = v_notificationHandlerMap[message.method()];
            v_notificationMutex.unlock();
            notif->processNotification(message);
        }else if(message.type() == JsonRpcMessage::Result || message.type() == JsonRpcMessage::Error){
            JsonRpcResponseHandler *rep = v_currentRequest.take(message.id());
            rep->processResult(message);
        }
    }
}
